﻿using System.ComponentModel;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using Eva.Core.Security;
using Newtonsoft.Json.Linq;
using NPOI.SS.UserModel;
using NPOI.SS.Util;

namespace Utilities
{
    public class Gx
    {
        /// <summary>
        /// 解决方案路径
        /// </summary>
        private static string SlnPath { get; set; }

        public Gx(string _slnPath)
        {
            SlnPath = _slnPath;
        }

        //全局锁，用在log里
        private static readonly object Olock = new();

        #region 常量
        /// <summary>
        /// 默认密码
        /// </summary>
        public const string _DEFAULT_PASSWORD = "123456";

        /// <summary>
        /// Des加密用的key
        /// </summary>
        private const string _DES_KEY = "zyzztop.";

        /// <summary>
        /// 数据库中固定字段，原本是ClientID
        /// </summary>
        public const string _DB_FIELD_NAME_KEY = "GroupInfoID";

        /// <summary>
        /// 用户登录类型ID，对应登录用户类型，保存的值为 GroupInfo.ID 或 Regulator.ID
        /// </summary>
        public const string _LOGIN_TYPE_ID_KEY = "LoginTypeID";

        /// <summary>
        /// 登录用户ID的Key，对应登录用户类型，保存的值为 User.ID 或 RegulatorUser.ID
        /// </summary>
        public const string _USERID_KEY = "UserID";

        /// <summary>
        /// 登录用户名称的Key
        /// </summary>
        public const string _USERNAME_KEY = "UserName";

        /// <summary>
        /// 登录编号的Key，对应登录用户类型，保存的值为 GroupInfo.Code 或 Regulator.Code
        /// </summary>
        public const string _LOGIN_CODE_KEY = "LoginCode";

        /// <summary>
        /// 登录用户类型的Key，1集团，2监管部门，3超级用户
        /// </summary>
        public const string _LOGIN_USER_TYPE_KEY = "LoginUserType";

        /// <summary>
        /// 登录用户所有角色中所有部门ID集合的Key
        /// 保存的值为，当前用户所有角色选择的部门IDs或全部
        /// </summary>
        public const string _LOGIN_USER_ROLE_DEPARTMENT_KEY = "LoginUserRoleDepartment";

        /// <summary>
        /// 登录用户所有角色中所有类型为矿山的部门ID集合的key
        /// </summary>
        public const string _LOGIN_USER_KUANG_SHAN_DEPARTMENT_KEY = "LoginUserKuangShanDepartment";

        /// <summary>
        /// 登录用户是哪些仓库管理员的仓库IDs
        /// 保存的值为，当前登录用户是哪些仓库管理员，返回对应的仓库ID
        /// </summary>
        public const string _LOGIN_USER_WAREHOUSE_IDS_KEY = "LoginUserWarehouseIDs";

        /// <summary>
        /// 登录用户按数据归属的方式，能有哪些仓库
        /// 保存的值为，根据当前登录用户所有的角色，如果角色中有设置的全部，则返回全部启用的仓库id；否则，根据角色设置的部门，返回仓库数据中设置的数据归属与之匹配或仓库数据中设置的为不限的仓库id;
        /// </summary>
        public const string _LOGIN_USER_WAREHOUSE_IDS_WITH_DATA_DEPARTMENT_KEY = "LoginUserWarehouseIDsWithDataDepartment";

        /// <summary>
        /// 登录监管部门用户设置的哪些区域所对应的部门IDs
        /// </summary>
        public const string _LOGIN_REGULATOR_DEPARTMENT_IDS_KEY = "LoginRegulatorDepartmentIDs";

        /// <summary>
        /// 分页时每页数据量
        /// </summary>
        public const int _PAGE_SIZE = 20;

        /// <summary>
        /// 数据权限为不限时的值
        /// </summary>
        public const int _NO_DATA_PERMISSION_VALUE = -1;
        #endregion

        #region DES加密  DesEncrypt
        /// <summary>
        /// DES加密
        /// </summary>
        /// <param name="str">明文</param>
        /// <param name="key">密钥</param>
        /// <returns></returns>
        public static string DesEncrypt(string str, string key = _DES_KEY)
        {
            return DESHelper.Encrypt(str, key);
        }
        #endregion

        #region DES解密  DesDecrypt
        /// <summary>
        /// DES解密
        /// </summary>
        /// <param name="str">密文</param>
        /// <param name="key">密钥</param>
        /// <returns></returns>
        public static string DesDecrypt(string str, string key = _DES_KEY)
        {
            return DESHelper.Decrypt(str, key);
        }
        #endregion

        #region MD5散列  MD5
        /// <summary>
        /// MD5散列
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string MD5(string str)
        {
            return MD5Helper.MD5(str);
        }
        #endregion

        #region HMAC_SHA256加密  HMAC_SHA256
        /// <summary>
        /// HMAC_SHA256加密
        /// </summary>
        /// <param name="key"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public static byte[] HMAC_SHA256(byte[] key, string msg)
        {
            using (HMACSHA256 mac = new HMACSHA256(key))
            {
                return mac.ComputeHash(Encoding.UTF8.GetBytes(msg));
            }
        }
        #endregion

        #region 记录本地日志  Log
        /// <summary>
        /// 记录本地日志
        /// </summary>
        /// <param name="con">日志记录的内容</param>
        public static void Log(string con, string fileNamePre = "", string fileNameMiddle = "", string fileNameEnd = "")
        {
            ThreadPool.QueueUserWorkItem(delegate (object state)
            {
                object olock = Olock;
                lock (olock)
                {
                    try
                    {
                        if (fileNameMiddle.IsEmpty())
                        {
                            fileNameMiddle = DateTime.Now.ToString("yyyy.MM.dd-HH");
                        }

                        string fileName = $"{fileNamePre}{fileNameMiddle}{fileNameEnd}.txt";
                        string path = SlnPath + @"/Logs/";
                        DirectoryInfo info = new(path);
                        if (!info.Exists)
                        {
                            info.Create();
                        }

                        using (FileStream stream = new(path + fileName, FileMode.Append, FileAccess.Write))
                        {
                            StreamWriter writer = new(stream);
                            writer.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fffffff"));
                            writer.WriteLine(con);
                            writer.WriteLine();
                            writer.WriteLine("-----------------------------------------------------------------");
                            writer.Flush();
                            writer.Close();
                        }
                    }
                    catch { }
                }
            });
        }
        #endregion

        #region 返回枚举的描述信息  GetEnumDescription
        /// <summary>
        /// 返回枚举的描述信息
        /// </summary>
        /// <typeparam name="TEnum"></typeparam>
        /// <param name="enumVal">枚举值</param>
        /// <param name="nullVal">如果为空或异常时返回的内容，默认为空串</param>
        /// <returns></returns>
        public static string GetEnumDescription<TEnum>(TEnum enumVal, string nullVal = "")
        {
            try
            {
                FieldInfo fieldInfo = enumVal.GetType().GetField(enumVal.ToString());
                DescriptionAttribute[] descriptionAttributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
                return descriptionAttributes.Length > 0 ? descriptionAttributes[0].Description : enumVal.ToString();
            }
            catch (Exception)
            {
                return nullVal;
            }
        }
        #endregion

        #region 根据枚举类型得到定义的名称  GetEnumName
        /// <summary>
        /// 根据枚举类型得到定义的名称
        /// </summary>
        /// <param name="type"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string GetEnumName(Type type, int value)
        {
            string result = "-";
            result = Enum.IsDefined(type, value) ? Enum.GetName(type, value) : result;
            return result;
        }
        #endregion

        #region 根据枚举值得到枚举对象  GetEnumByValue
        /// <summary>
        /// 根据枚举值得到枚举对象
        /// </summary>
        /// <typeparam name="T">枚举</typeparam>
        /// <param name="value">枚举值</param>
        /// <returns></returns>
        public static T GetEnumByValue<T>(int value)
        {
            return (T)Enum.ToObject(typeof(T), value);
        }
        #endregion

        #region 生成Code  GetCode
        /// <summary>
        /// 生成Code，主体内容为yyyyMMddhhmmssfff
        /// </summary>
        /// <param name="left">前缀</param>
        /// <param name="right">后缀</param>
        /// <returns></returns>
        public static string GetCode(string left = null, string right = null)
        {
            string body = left + "-" + DateTime.Now.ToString("yyMMddHHmmssfff");
            if (right.IsNotEmpty())
            {
                body = body + "-" + right;
            }

            return body;
        }
        #endregion

        #region 得到一个N位数的随机数
        /// <summary>
        /// 得到一个N位数的随机数
        /// </summary>
        /// <returns></returns>
        public static string GetRandom(int n = 6)
        {
            if (n >= 10)
            {
                throw new Exception("随机数最大只能生成9位数！");
            }

            Random ran = new();
            int min = "1".ToString().PadRight(n, '0').ToInt();
            int max = "1".ToString().PadRight(n + 1, '0').ToInt();
            return ran.Next(min, max).ToString();
        }
        #endregion

        #region Excel导出相关
        //得到单元格样式
        public static ICellStyle GetStyle(IWorkbook workbook, double fontSize = 10.5, bool isBold = false, string fontName = "宋体", bool isWrap = true, HorizontalAlignment horizontalAlignment = HorizontalAlignment.Center)
        {
            ICellStyle style = workbook.CreateCellStyle();
            style.WrapText = isWrap;
            style.VerticalAlignment = VerticalAlignment.Center;
            style.Alignment = horizontalAlignment;
            style.SetFont(GetFont(workbook, fontSize, isBold, fontName));
            style.BorderTop = BorderStyle.Thin;
            style.BorderRight = BorderStyle.Thin;
            style.BorderBottom = BorderStyle.Thin;
            style.BorderLeft = BorderStyle.Thin;
            return style;
        }

        //得到字体
        public static IFont GetFont(IWorkbook workbook, double fontSize, bool isBold = false, string fontName = "宋体")
        {
            IFont font = workbook.CreateFont();
            font.FontHeight = GetExcelFontSize(fontSize);
            font.IsBold = isBold;
            font.FontName = fontName;
            return font;
        }

        //合并单元格
        public static void MergeCell(int firstRow, int lastRow, int firstCol, int lastCol, ISheet sheet)
        {
            CellRangeAddress range = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol);
            sheet.AddMergedRegion(range);
            RegionUtil.SetBorderTop(1, range, sheet);
            RegionUtil.SetBorderRight(1, range, sheet);
            RegionUtil.SetBorderBottom(1, range, sheet);
            RegionUtil.SetBorderLeft(1, range, sheet);
        }

        public static void SetBorder(ICellStyle style)
        {
            style.BorderTop = BorderStyle.Thin;
            style.BorderRight = BorderStyle.Thin;
            style.BorderBottom = BorderStyle.Thin;
            style.BorderLeft = BorderStyle.Thin;
        }

        public static string GetStr(JToken val)
        {
            if (val.IsEmpty())
            {
                return "";
            }
            return val.ToString();
        }

        public static short GetExcelRowHeight(short n)
        {
            return (short)(n * 15);
        }

        //得到列宽
        public static int GetExcelColWeight(int n)
        {
            return n * 32;
        }

        //得到字体大小
        public static double GetExcelFontSize(double n)
        {
            return n * 20;
        }
        #endregion

        public static byte[] DownloadImageAsByteArray(string url)
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/octet-stream"));

                var response = client.GetAsync(url).Result;
                response.EnsureSuccessStatusCode();

                return response.Content.ReadAsByteArrayAsync().Result;
            }
        }
    }
}
